﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using MemoryDuosRankings;

namespace MemoryDuosInterfaz
{
    /// <summary>
    /// Tablero que posee parte de la lógica de la partida.
    /// </summary>
    public class Tablero : MemoryDuosInterfaz.ITablero
    {
        internal List<Coordenadas> destapadas;

        private int fallos;

        private int maxParejas;

        private int parejasConsecutivas;

        /// <summary>
        /// Construye un tablero del tamaño definido con una lista de imagenes
        /// </summary>
        /// <param name="alto">Altura del tablero</param>
        /// <param name="ancho">Anchura del tablero</param>
        /// <param name="imagenes">Lista de Imágenes</param>
        public Tablero(int alto, int ancho)
        {
            Ancho = ancho;
            Alto = alto;
            Imagenes = new Bitmap[Alto, Ancho];
            EstadoTablero = new Boolean[Alto, Ancho];
            HayImagen = new Boolean[Alto, Ancho];
            fallos = 0;
            maxParejas = 0;
            parejasConsecutivas = 0;
        }

        public Tablero(int alto, int ancho, List<Bitmap> imagenes, String galería)
            : this(alto, ancho)
        {
            destapadas = new List<Coordenadas>();
            Galería = galería;
            listaImagenes = imagenes;
            InicializarTablero(listaImagenes);
        }

        public Tablero(int alto, int ancho, List<Bitmap> imagenes, String galería, Ranking rnk)
            : this(alto, ancho)
        {
            Partida = rnk;
            destapadas = new List<Coordenadas>();
            Galería = galería;
            listaImagenes = imagenes;
            InicializarTablero(listaImagenes);
        }

        public int Alto { get; set; }

        public int Ancho { get; set; }

        public Button[,] ArrayBotones { get; set; }

        public Boolean[,] EstadoTablero { get; set; }

        public String Galería { get; set; }

        public Boolean[,] HayImagen { get; set; }

        public Bitmap[,] Imagenes { get; set; }

        public List<Bitmap> listaImagenes { get; set; }

        public Ranking Partida { get; set; }

        public void ActualizarEstadoPartida()
        {
            HayImagen = new Boolean[Alto, Ancho];
            foreach (Tuple<int, int, int> par in Partida.acertadas)
            {
                this.SetEstado(new Coordenadas(par.Item1, par.Item2), true);
                this.SetImagen(par.Item1, par.Item2, listaImagenes.ElementAt(par.Item3));
            }
            InicializarTablero(listaImagenes);
            foreach (var buton in ArrayBotones)
            {
                if (GetEstado(obtenerCoordenadaBoton(buton)) == true)
                    buton.BackgroundImage = GetImagen(obtenerCoordenadaBoton(buton));
            }
        }

        public void almacenarCoordenadasParejasLista(Coordenadas coordenadas)
        {
            destapadas.Add(coordenadas);
        }

        public bool comprobarCartasLista()
        {
            if (destapadas.Count == 2)
            {
                Bitmap imagenCarta1 = this.GetImagen(destapadas.ElementAt(0));
                Bitmap imagenCarta2 = this.GetImagen(destapadas.ElementAt(1));
                // comprobamos si las cartas destapadas son iguales
                if (!imagenCarta1.Equals(imagenCarta2))
                {
                    fallos++;
                    if (parejasConsecutivas > maxParejas) maxParejas = parejasConsecutivas;
                    parejasConsecutivas = 0;
                    return false;
                }
            }
            parejasConsecutivas++;
            return true;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="timerCartas"></param>
        /// <param name="tiempo">Tiempo de duración de Partida</param>
        /// <param name="partida"></param>
        public void destaparCarta(object sender, EventArgs e, Timer timerCartas, Timer timerInactividad, TimeSpan tiempo, Form partida)
        {
            Coordenadas coordenadas = obtenerCoordenadaBoton((Button)sender);
            // destapamos la carta si su estado es false
            if (timerCartas.Enabled == true)
                return;
            if (!this.GetEstado(coordenadas) && destapadas.Count <= 2)
            {
                almacenarCoordenadasParejasLista(coordenadas);
            }
            if (!this.GetEstado(coordenadas) && destapadas.Count == 1)
            {
                ((Button)sender).BackgroundImage = this.GetImagen(coordenadas);
                this.SetEstado(coordenadas, true);
                timerInactividad.Start();
            }
            if (!this.GetEstado(coordenadas) && destapadas.Count == 2)
            {
                ((Button)sender).BackgroundImage = this.GetImagen(coordenadas);
                timerInactividad.Stop();
                this.SetEstado(coordenadas, true);
                if (!comprobarCartasLista()) { timerCartas.Start(); } else destapadas.Clear();
            }
            if (this.EsFinPartida())
            {
                FinalizarPartida(tiempo);
                EstadisticasPartida fin = new EstadisticasPartida(tiempo, parejasConsecutivas, fallos, this);
                fin.ShowDialog(partida);
            }
        }

        public bool EsFinPartida()
        {
            List<Boolean> Lista = EstadoTablero.Cast<Boolean>().ToList();
            bool existe = Lista.Exists(r => r == false);
            return !existe;
        }

        /// <summary>
        /// Comprueba que las coordenadas pasadas como parámetro son válidas
        /// </summary>
        /// <param name="alto"></param>
        /// <param name="ancho"></param>
        /// <returns>Válido o no válido</returns>
        public bool esValido(int alto, int ancho)
        {
            //Controlar que no nos salimos del tablero
            try
            {
                var b = HayImagen[alto, ancho];
                var c = Imagenes[alto, ancho];
                var d = EstadoTablero[alto, ancho];
                return true;
            }
            catch (IndexOutOfRangeException)
            {
                return false;
            }
        }

        public void FinalizarPartida(TimeSpan tiempo)
        {
            DAL.Instance.FinalizarRanking(this.Partida, tiempo);
        }

        /// <summary>
        /// Devuelve si la carta esta destapada definitivamente en el tablero o no
        /// </summary>
        /// <returns></returns>
        public bool GetEstado(Coordenadas coordenadas)
        {
            if (esValido(coordenadas.Y, coordenadas.X))
            {
                return EstadoTablero[coordenadas.Y, coordenadas.X];
            }
            return false;
        }

        public Bitmap GetImagen(Coordenadas coordenadas)
        {
            if (esValido(coordenadas.Y, coordenadas.X))
            {
                return Imagenes[coordenadas.Y, coordenadas.X];
            }
            return null;
        }

        public Coordenadas obtenerCoordenadaBoton(Button boton)
        {
            for (int i = 0; i < ArrayBotones.GetLength(0); i++)
            {
                for (int j = 0; j < ArrayBotones.GetLength(1); j++)
                {
                    if (boton.Equals(ArrayBotones[i, j]))
                    {
                        return new Coordenadas(i, j);
                    }
                }
            }
            return null;
        }

        public void PausarPartida(TimeSpan tiempo)
        {
            if (destapadas.Count == 1) { TaparCarta(destapadas.ElementAt(0)); }
            var lista = new List<Tuple<int, int, int>>();
            for (int i = 0; i < EstadoTablero.GetLength(0); i++)
            {
                for (int j = 0; j < EstadoTablero.GetLength(1); j++)
                {
                    if (GetEstado(new Coordenadas(i, j)))
                    {
                        lista.Add(Tuple.Create(i, j, listaImagenes.IndexOf(GetImagen(new Coordenadas(i, j)))));
                    }
                }
            }

            DAL.Instance.PausarRanking(this.Partida, tiempo, Galería, lista);
        }

        public void SetEstado(Coordenadas coordenadas, bool estadoNuevo)
        {
            if (esValido(coordenadas.Y, coordenadas.X))
            {
                EstadoTablero[coordenadas.Y, coordenadas.X] = estadoNuevo;
            }
        }

        /// <summary>
        /// Inserta la imagen en las coordenadas indicadas
        /// </summary>
        /// <param name="alto">Posición deseada</param>
        /// <param name="ancho">Posición deseada</param>
        /// <param name="imagen">Imagen a insertar</param>
        public void SetImagen(int alto, int ancho, Bitmap imagen)
        {
            if (esValido(alto, ancho))
            {
                Imagenes[alto, ancho] = imagen;
                HayImagen[alto, ancho] = true;
            }
        }

        public bool SonIguales(Coordenadas coordenadas1, Coordenadas coordenadas2)
        {
            //Retorna si dos imagenes son iguales
            if (esValido(coordenadas1.Y, coordenadas1.X) && esValido(coordenadas2.Y, coordenadas2.X))
            {
                if (Imagenes[coordenadas1.Y, coordenadas1.X].Equals(Imagenes[coordenadas2.Y, coordenadas2.X]))
                    return true;
            }

            return false;
        }

        public void TaparCarta(Coordenadas c1)
        {
            ArrayBotones[c1.Y, c1.X].BackgroundImage = MemoryDuosInterfaz.Properties.Resources.MEMORYDUOS;
            this.SetEstado(c1, false);
        }

        public void TaparCartas(Coordenadas c1, Coordenadas c2)
        {
            ArrayBotones[c1.Y, c1.X].BackgroundImage = MemoryDuosInterfaz.Properties.Resources.MEMORYDUOS;
            ArrayBotones[c2.Y, c2.X].BackgroundImage = MemoryDuosInterfaz.Properties.Resources.MEMORYDUOS;
            this.SetEstado(c1, false);
            this.SetEstado(c2, false);
        }

        public void TaparCartasDiferentes(Timer timerCartas)
        {
            TaparCartas(destapadas.ElementAt(0), destapadas.ElementAt(1)); destapadas.Clear(); timerCartas.Stop();
        }

        private bool ExisteAcertada(Bitmap imagen)
        {
            foreach (Tuple<int, int, int> par in Partida.acertadas)
            {
                if (imagen.Equals(listaImagenes.ElementAt(par.Item3))) return true;
            }
            return false;
        }

        /// <summary>
        /// Inicializa el tablero, con las imágenes que le pasemos como parámetro
        /// </summary>
        /// <param name="imagenes">Lista de Imágenes</param>
        private void InicializarTablero(List<Bitmap> imagenes)
        {
            Random random = new Random();

            foreach (Bitmap img in imagenes)
            {
                if (ExisteAcertada(img)) continue; //Si la imagen ya existe nos la botamos
                for (int i = 0; i <= 1; i++)
                {
                    int alto1 = random.Next(0, Alto);
                    int ancho1 = random.Next(0, Ancho);
                    if (!HayImagen[alto1, ancho1])
                    {
                        SetImagen(alto1, ancho1, img);
                    }
                    else i--;
                }
            }
        }

        private List<Coordenadas> ObtenerListaCoordenadasAcertadas(List<Tuple<int, int>> lista)
        {
            var devolver = new List<Coordenadas>();
            foreach (var par in lista)
            {
                devolver.Add(new Coordenadas(par.Item1, par.Item2));
            }
            return devolver;
        }


    }
}

